//=====================================================================
//    COPYRIGHT(C) Innobeam
//    ALL RIGHTS RESERVED
//=====================================================================
//Filename    : SPIMasterEPD.v
//Created On  : 2018-12-18
//Author      : Chao
//Description :	SPI master for EPD
//Include     : 
//Modification: 
//=====================================================================
module SPIMasterEPD(
	iClk,
	iRst_n,
	
	ivData,
	iStart,
	ovRxData,
	oDone,
	
	oSCLK,
	oSI,
	iSO,
	oCS_n
	);
//========================================================================
//    parameter
//========================================================================
parameter		SCK_IDLE_STATE = 1'b0;		//SCK idle time:0:low;1:high
parameter		FREP	=	2			;  //oSCK cycle = FREP * 2 * iClk cycle(must >=2)
//========================================================================
//    port
//========================================================================	
	input 				iClk;
	input 				iRst_n;

	input 	[7:0]		ivData;
	input				iStart;

	output	[7:0]		ovRxData;
	output				oDone;
	
	output 				oSCLK;
	output 				oSI;
	input				iSO;
	output				oCS_n;
//========================================================================
//    signal
//========================================================================
	reg		[7:0]		ovRxData;
	reg					rDone;
	reg					rDone_buf;
	reg					rDone_bufa;
	reg 				oSCLK;
	reg					oSI;
	reg					oCS_n;
	reg					rRcvDatEn;
	reg		[7:0]		rvData;
	
	reg		[7:0]		rvClk_cnt	;
	reg		[5:0]		rvBitCnt;
	reg					rSCK_buf	;
	reg					rSCK_bufreg;
	wire 	SCK_posedge;
	wire 	SCK_negedge;
	
assign oDone = (rDone&!rDone_buf);	
	
//change rRcvDatEn to 1:TREAT input data AS valid Data and save them to SRAM
always @(posedge iClk or negedge iRst_n)begin
if(iRst_n==1'b0)begin
	rRcvDatEn <= 1'b0;
	end
else begin
	if(iStart == 1'b1)begin//
		rRcvDatEn <= 1'b1;
		end
	else if(rDone == 1'b1)begin//
		rRcvDatEn <= 1'b0;
		end
	else begin//
		rRcvDatEn <= rRcvDatEn;
		end
	end 
end
//6M25 SCLK
//rvClk_cnt (clkoc divide)
always@(posedge iClk or negedge iRst_n)begin
	if(iRst_n == 1'b0)begin
		rvClk_cnt <= 8'd0;
		end
	else begin
		if(rRcvDatEn == 1'b1)begin
			if(rvClk_cnt >= (FREP-1)) begin
				rvClk_cnt <= 8'd0;
				end
			else begin
				rvClk_cnt <= rvClk_cnt + 1'b1;
				end
			 end
		 else begin
			 rvClk_cnt <= 8'd0;
		 end
	end
	end
	
	//generate oSCK	signal
	always@(posedge iClk or negedge iRst_n)begin
	if(iRst_n==1'b0)begin
		if(SCK_IDLE_STATE == 0)
			rSCK_buf <= 1'b0;
		else 
			rSCK_buf <= 1'b1;
		end
	else begin
		if(rRcvDatEn == 1'b1)begin
			if(rvClk_cnt == (FREP - 1'b1))
				rSCK_buf <= ~rSCK_buf;
			else
				rSCK_buf <= rSCK_buf;
			 end
		 else begin
			 rSCK_buf <= 1'b0;
			 end
		end
	end
	
	always@(posedge iClk or negedge iRst_n)begin
	 if(iRst_n == 1'b0)begin
		 rSCK_bufreg <= 1'b0;
		 end
	 else begin
		 rSCK_bufreg <= rSCK_buf;
		 end
	 end
	 
	 always@(posedge iClk or negedge iRst_n)begin
	 if(iRst_n == 1'b0)begin
		 rDone_buf <= 1'b1;
		 rDone_bufa <= 1'b1;
		 end
	 else begin
		 rDone_buf <= rDone;
		 rDone_bufa <= rDone_buf;
		 end
	 end
	
	assign SCK_posedge=(rSCK_buf&!rSCK_bufreg);				//ClkCnt==01
	assign SCK_negedge=(!rSCK_buf&rSCK_bufreg);				//ClkCnt==11
	
//logic
		always@(posedge iClk or negedge iRst_n)begin
		if(!iRst_n)begin
			ovRxData	<= 8'h0;	
			rDone		<= 1'b1;
			oSCLK		<= 1'b0;
			oSI			<= 1'b1;
			oCS_n		<= 1'b1;
			rvData 		<= 8'h0;
			rvBitCnt	<= 6'd0;
		end
		else begin
			case (rvBitCnt)
//waiting for start input and then latch input data
			8'd0: begin								
					if (rDone_bufa & iStart) begin
						ovRxData	<= ovRxData;	
						rDone		<= 1'b0;
						oSCLK		<= 1'b0;
						oSI			<= 1'b0;
						oCS_n		<= 1'b1;
						rvData 		<= ivData;
						rvBitCnt	<= 6'd1;
						end
				end
//write Header
			8'd1,8'd3,8'd5,8'd7,8'd9,8'd11,8'd13,8'd15: begin
					if (SCK_negedge) begin
						ovRxData	<= 8'h0;	
						rDone		<= 1'b0;
						oSCLK		<= 1'b0;
						oSI			<= rvData[7];
					//	oSI			<= rvData[0];
						oCS_n		<= 1'b0;
						rvData 		<= {rvData[6:0],1'b1};
					//	rvData 		<= {1'b1,rvData[7:1]};
						rvBitCnt	<= rvBitCnt+6'd1;
						end
					end
			8'd2,8'd4,8'd6,8'd8,8'd10,8'd12,8'd14,8'd16: begin
					if (SCK_posedge) begin
						ovRxData	<= 8'h0;	
						rDone		<= 1'b0;
						oSCLK		<= 1'b1;
						oSI		<= oSI;
						oCS_n		<= 1'b0;
						rvData <= rvData;
						rvBitCnt	<= rvBitCnt+6'd1;
						end
					end				
//End SPI write and read
			8'd17:begin
					if(SCK_negedge)begin
						ovRxData	<= ovRxData;	
						rDone		<= 1'b0;
						oSCLK		<= 1'b0;
						oSI			<= 1'b0;
						oCS_n		<= 1'b0;
						rvData 		<= 8'h0;
						rvBitCnt	<= rvBitCnt+6'd1;
					end
				end
			default: begin
						ovRxData	<= ovRxData;	
						rDone		<= 1'b1;
						oSCLK		<= 1'b0;
						oSI		<= 1'b0;
						oCS_n		<= 1'b1;
						rvData <= 8'h0;
						rvBitCnt	<= 6'd0;
					end
			endcase
		end
	end
endmodule